#!/bin/bash
# shellcheck disable=all # Jinja2 template can not be parsed with shellcheck

set -u -o pipefail

VERSION=0.2
CWD="$(realpath "${0%}")"
CWD="${CWD%/*}"

DAOS_INSTALL_DIR="{{ daos_runtime_dir }}/install"
DAOS_VENV_DIR="{{ daos_runtime_dir }}/virtualenvs"
DAOS_SOURCE_DIR="{{ daos_source_dir }}"
{% if daos_ofi_interface is defined %}
OFI_INTERFACE="{{ daos_ofi_interface }}"
{% endif %}

PYTHON_EXE=python
MODULE_EXE=module

ANSI_COLOR_BLACK=30
ANSI_COLOR_RED=31
ANSI_COLOR_GREEN=32
ANSI_COLOR_YELLOW=33
ANSI_COLOR_BLUE=34
ANSI_COLOR_MAGENTA=35
ANSI_COLOR_CYAN=36
ANSI_COLOR_WHITE=37
ANSI_COLOR_BRIGHT_BLACK=90
ANSI_COLOR_BRIGHT_RED=91
ANSI_COLOR_BRIGHT_GREEN=92
ANSI_COLOR_BRIGHT_YELLOW=93
ANSI_COLOR_BRIGHT_BLUE=94
ANSI_COLOR_BRIGHT_MAGENTA=95
ANSI_COLOR_BRIGHT_CYAN=96
ANSI_COLOR_BRIGHT_WHITE=97

TRACE_LEVEL_QUIET=-1
TRACE_LEVEL_STANDARD=0
TRACE_LEVEL_VERBOSE=1
TRACE_LEVEL_DEBUG=2
TRACE_LEVEL=$TRACE_LEVEL_STANDARD

START_CLEANUP="false"
END_CLEANUP="false"

function debug
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_DEBUG ]]
	then
		echo -e "[\e[${ANSI_COLOR_GREEN}mDEBUG  \e[00m] $@"
	fi
}


function info
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_VERBOSE ]]
	then
		echo -e "[\e[${ANSI_COLOR_CYAN}mINFO   \e[00m] $@"
	fi
}

function warning
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_STANDARD ]]
	then
		echo -e "[\e[${ANSI_COLOR_YELLOW}mWARNING\e[00m] $@" 1>&2
	fi
}

function error
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_STANDARD ]]
	then
		echo -e "[\e[${ANSI_COLOR_BRIGHT_RED}mERROR  \e[00m] $@" 1>&2
	fi
}

function fatal
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_STANDARD ]]
	then
		echo -e "[\e[${ANSI_COLOR_RED}mFATAL  \e[00m] $@" 1>&2
	fi
	exit 1
}

function check_cmds
{
	for cmd in $@
	do
		{ hash $cmd > "/dev/null" 2>&1 ; } || { fatal "$cmd command not installed" ; }
	done
}

function usage
{
	cat <<- EOF
		usage: daos-launch.sh [OPTIONS] [-- ARGS]

		Launch DAOS avocado functional tests

		Options:
		   -s, --start-cleanup      cleanup platform before starting tests
		   -e, --end-cleanup        cleanup platform after running the tests
		   -h, --help               show this help message and exit
		   -V, --version            show version number
		   -q, --quiet              quiet mode
		   -v, --verbose            verbose mode
		   -D, --debug              debug mode
	EOF
}

function run
{
	if [[ $TRACE_LEVEL -ge $TRACE_LEVEL_STANDARD ]]
	then
		"$@"
	else
		"$@" &> /dev/null
	fi
}

function cleanup
{
	info "Clean up of local server"
	run sudo systemctl stop daos_server
	run sudo rm -rf /var/run/daos_server
	run sudo mkdir -p /var/run/daos_server

	info "Stopping all DAOS related processes"
	run sudo killall -q -9 avocado orterun mpirun orted daos_server daos_io_server daos_agent

	info "Cleaning mount points of local server"
	for index in {0..3}
	do
		mountpoint="/mnt/daos$index"
		if run mountpoint -q "$mountpoint" ; then
			info "Cleaning mount points $mountpoint of host $host"
			run sudo rm -fr $mountpoint/*
			run sudo umount $mountpoint
		fi
	done

	for index in {0..1}
	do
		bdev="/dev/pmem$index"
		if run test -b "$bdev" ; then
			info "Cleaning persistent memory $bdev of host $host"
			run sudo wipefs -a "$bdev"
		fi
	done

	info "Cleaning huge pages"
	run sudo ipcrm --all=shm
	run sudo /bin/rm -f "/dev/hugepages/spdk_*"
}

{% raw %}
opts=()
args=()
for item in "$@" ; do
	if [[ ${#args[@]} -eq 0 && "$item" != "--" ]] ; then
		[[ ${item::1} == "-" ]] || fatal "unrecognized option \"$item\""
		opts+=("$item")
	else
		args+=("$item")
	fi
done
args=("${args[@]:1}")
{% endraw %}

OPTIONS=$(getopt -o "sehVvDq" --long "start-cleanup,end-cleanup,help,version,verbose,debug,quiet" -- "${opts[@]}") || exit 1
eval set -- "$OPTIONS"
while true
do
	case "$1" in
		-s|--start-cleanup) START_CLEANUP="true" ; shift 1;;
		-e|--end-cleanup) END_CLEANUP="true" ; shift 1;;
		-h|--help) usage ; exit 0;;
		-V|--version) echo "daos-launch.sh version=$VERSION" ; exit 0 ;;
		-v|--verbose) TRACE_LEVEL="$TRACE_LEVEL_VERBOSE" ; shift 1 ;;
		-D|--debug) TRACE_LEVEL="$TRACE_LEVEL_DEBUG" ; set -x ; shift 1 ;;
		-q|--quiet) TRACE_LEVEL="$TRACE_LEVEL_QUIET" ; shift 1 ;;
		--) shift ; break ;;
		*) fatal "unrecognized option" ;;
	esac
done

check_cmds $MODULE_EXE

if "$START_CLEANUP" ; then
	cleanup

	info "Cleaning NLT logs"
	run /bin/rm -f "$DAOS_SOURCE_DIR"/dnt.* "$DAOS_SOURCE_DIR"/nlt-* "$DAOS_SOURCE_DIR"/vgcore.*
fi

info "Setting python simulation environment"
source "$DAOS_VENV_DIR/bin/activate"
if [[ ${PYTHONPATH:+x} ]] ; then
	export PYTHONPATH="$DAOS_INSTALL_DIR/lib/daos/TESTING/ftest/util:$PYTHONPATH"
else
	export PYTHONPATH="$DAOS_INSTALL_DIR/lib/daos/TESTING/ftest/util"
fi
cd "$DAOS_SOURCE_DIR"
source utils/sl/setup_local.sh

info "Setting MPI simulation environment"
if run $MODULE_EXE is-avail mpi/mpich-x86_64 ; then
	run $MODULE_EXE load mpi/mpich-x86_64
fi

info "Fixing daos_server_helper"
run sudo -E "$DAOS_SOURCE_DIR/utils/setup_daos_server_helper.sh"
run chmod -x "$DAOS_INSTALL_DIR/bin/daos_server_helper"
run sudo prlimit --nofile=1024:262144 --pid $$

info "Starting NLT tests"
pushd "$DAOS_SOURCE_DIR" > /dev/null
{% if daos_ofi_interface is defined %}
run env OFI_INTERFACE=$OFI_INTERFACE $PYTHON_EXE utils/node_local_test.py "${args[@]}"
{% else %}
run $PYTHON_EXE utils/node_local_test.py "${args[@]}"
{% endif %}
rc=$?
popd > /dev/null
deactivate

if "$END_CLEANUP" ; then
	cleanup
fi

exit $rc
